#include <QtGui>
#include "mainwindow.h"
#include "defines.h"
#include "configquikman.h"

QStringList     MainWindow::manpaths;
QStringList     MainWindow::suffixes;
QStringList     MainWindow::msuffixes;
QTextStream     MainWindow::cout(stdout);

MainWindow::MainWindow(QApplication *app1)
{
    app = app1;
    currentName    = "";
    currentSection = "";
    currentPathid  = "";

    createStatusBar();
    createActions();
    createMenus();
    createDockingWindow();
    //createToolBar();
    createCentralWidget();
    appName = tr("QuickMan")+" - " +QString::number( QUIKMAN_VERSION_MAJOR ) + "." + QString::number( QUIKMAN_VERSION_MINOR ) + "." + QString::number( QUIKMAN_VERSION_REVISION );

    p = new QProcess();
 }


void MainWindow::createActions()
{

    clearRecentAct = new QAction(tr("&Clear Recent"), this);
    clearRecentAct->setShortcut(tr("Ctrl+Alt+R"));
    clearRecentAct->setStatusTip(tr("Clear the manual viewer session."));
    connect(clearRecentAct, SIGNAL(triggered()), this, SLOT(clearRecent()));

    clearHistoryAct = new QAction(tr("Clear &History"), this);
    clearHistoryAct->setShortcut(tr("Ctrl+Alt+H"));
    clearHistoryAct->setStatusTip(tr("Clear the manual viewer history."));
    connect(clearHistoryAct, SIGNAL(triggered()), this, SLOT(clearHistory()));

    exitAct = new QAction(tr("&Quit"), this);
    exitAct->setShortcut(tr("Ctrl+Q"));
    exitAct->setStatusTip(tr("Quit the application"));

    fexitAct = new QAction(tr("Force E&xit"), this);
    fexitAct->setShortcut(tr("Ctrl+X"));
    fexitAct->setStatusTip(tr("Exit without saving the session."));

    rebuildDbAct = new QAction(tr("Rebuild DB"), this);
    rebuildDbAct->setShortcut(tr("Ctrl+R"));
    rebuildDbAct->setStatusTip(tr("Rebuild the manual pages DB."));
    connect(rebuildDbAct, SIGNAL(triggered()), this, SLOT(rebuildDB()));

    searchAct = new QAction(tr("Search Within Manual"), this);
    searchAct->setCheckable( true );
    searchAct->setChecked( true );
    searchAct->setShortcut(QKeySequence::Find);
    searchAct->setStatusTip(tr("Search within the displayed manual page"));

    aboutAct = new QAction(tr("&About"), this);
    aboutAct->setStatusTip(tr("Show the quikman's about box"));
    connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
    connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
    connect(fexitAct, SIGNAL(triggered()), app, SLOT(quit()));
}

void MainWindow::createCentralWidget(){
    QWidget *central  = new QWidget( this );
    QVBoxLayout *vbox = new QVBoxLayout();
    central->setLayout( vbox );

    manText  = new QTextEdit(this);
    manText->show();
    manText->setReadOnly( true );
    manTextDoc = new QTextDocument(manText);
    manText->setDocument( manTextDoc );

    setCentralWidget(central);

    searchWidget      = new QWidget(central);
    QHBoxLayout *hbox = new QHBoxLayout();
    hbox->setSpacing( 0 );
    QHBoxLayout *hbox2 = new QHBoxLayout();
    hbox2->setSpacing( 0 );
    QVBoxLayout *vbox2 = new QVBoxLayout();
    vbox2->setSpacing( 0 );
    searchWidget->setLayout( vbox2 );
    //widget->setLayoutDirection( Qt::LeftToRight );
    vbox2->addWidget( new QLabel( QString(tr("Search Within Manual:")) ) );
    vbox2->addLayout( hbox );
    vbox2->addLayout( hbox2 );

    sCase  = new QCheckBox( QString("Match case"));
    sWords = new QCheckBox( QString("Whole word"));
    sText  = new QLineEdit( QString("") );
    sRegex = new QCheckBox( QString("Regex"));
    QPushButton     *sClear = new QPushButton( QString("Clear") );
    QPushButton     *sNext  = new QPushButton( QString("Next >") );
    QPushButton     *sPrev  = new QPushButton( QString("< Prev") );

    vbox->addWidget( searchWidget );
    vbox->addWidget( manText );

    connect( sClear, SIGNAL(clicked()), this, SLOT(searchClear()) );
    connect( sNext,  SIGNAL(clicked()), this, SLOT(fSearch()) );
    connect( sPrev,  SIGNAL(clicked()), this, SLOT(bSearch()) );
    connect(searchAct, SIGNAL(toggled(bool)), searchWidget, SLOT(setVisible(bool)));

    hbox->addWidget( sCase );
    hbox->addWidget( sWords );
    hbox->addWidget( sRegex );
    hbox->addStretch( 1 );

    hbox2->addWidget( sText );
    hbox2->addWidget( sPrev );
    hbox2->addWidget( sNext );
    hbox2->addWidget( sClear );
}

void MainWindow::createMenus()
{
    fileMenu = menuBar()->addMenu(tr("&File"));
    fileMenu->addAction(rebuildDbAct);
    fileMenu->addSeparator();
    //fileMenu->addAction(saveRecentAct);
    fileMenu->addAction(clearRecentAct);
    fileMenu->addAction(clearHistoryAct);
    fileMenu->addSeparator();
    fileMenu->addAction(exitAct);
    fileMenu->addAction(fexitAct);

    optMenu = menuBar()->addMenu(tr("&Options"));
    optMenu->addAction(searchAct );
    menuBar()->addSeparator();

    helpMenu = menuBar()->addMenu(tr("&Help"));
    helpMenu->addAction(aboutAct);
}

//void MainWindow::createToolBar()
//{
//    zToolBar = addToolBar(tr("Zoom"));
//    zToolBar->addAction(zInAct);
//    zToolBar->addAction(zOutAct);
//}

void MainWindow::setHeaderLabels(){
    QString shlist ("Name,Section,PathId,Date");
    rModel->setHorizontalHeaderLabels( shlist.split(",") );
    sList->setColumnWidth(0, 200);
    QString hhlist ("Name,Section,PathId,Date");
    hModel->setHorizontalHeaderLabels( hhlist.split(",") );
    hList->setColumnWidth(0, 200);
    QString ahlist ("Name,Section,PathId");
    aModel->setHorizontalHeaderLabels( ahlist.split(",") );
    aList->setColumnWidth(0, 200);
}

void MainWindow::createDockingWindow()
{
    QDockWidget *dock = new QDockWidget(tr("Manual Access "), this);
    dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
    notebook = new QTabWidget(this);
    notebook->show();

    rModel = new QStandardItemModel();
    hModel = new QStandardItemModel();
    aModel = new QStandardItemModel();



    sList = new QTreeView(notebook);
    sList->setModel( (QAbstractItemModel *)rModel);
    sList->setSelectionMode(QAbstractItemView::SingleSelection );
    hList = new QTreeView(notebook);
    hList->setModel( (QAbstractItemModel *)hModel);
    hList->setSelectionMode(QAbstractItemView::SingleSelection );
    aList = new QTreeView(notebook);
    aList->setModel( (QAbstractItemModel *)aModel);
    aList->sortByColumn( 0);
    aList->setSelectionMode(QAbstractItemView::SingleSelection );

    setHeaderLabels();
    //connect( (QAbstractItemView*)aList, SIGNAL(clicked(const QModelIndex &)), this, SLOT(openManualFromAll(const QModelIndex &)) );
    //connect( (QAbstractItemView*)hList, SIGNAL(clicked(const QModelIndex &)), this, SLOT(openManualFromHistory(const QModelIndex &)) );
    //connect( (QAbstractItemView*)sList, SIGNAL(clicked(const QModelIndex &)), this, SLOT(openManualFromRecent(const QModelIndex &)) );
    connect( (QAbstractItemView*)aList, SIGNAL(activated(const QModelIndex &)), this, SLOT(openManualFromAll(const QModelIndex &)) );
    connect( (QAbstractItemView*)hList, SIGNAL(activated(const QModelIndex &)), this, SLOT(openManualFromHistory(const QModelIndex &)) );
    connect( (QAbstractItemView*)sList, SIGNAL(activated(const QModelIndex &)), this, SLOT(openManualFromRecent(const QModelIndex &)) );
    //connect( (QAbstractItemModel*)aModel, SIGNAL(item_changed(const QStandardItem *)), this, SLOT(doNothing()) );

    notebook->addTab( aList, "Everything");
    notebook->addTab( sList, "Recent");
    notebook->addTab( hList, "History");
    dock->setWidget(notebook);
    addDockWidget(Qt::LeftDockWidgetArea, dock);
    optMenu->addAction(dock->toggleViewAction());

}


void MainWindow::createStatusBar()
{
    statusBar()->showMessage(tr("Ready"));
}


void MainWindow::closeEvent(QCloseEvent *event)
{
    this->saveModels();
    event->accept();
}

void MainWindow::about()
{
    QString abt( QUIKMAN_PROGRAM LINEBREAK );
    abt += QString(QUIKMAN_AUTHOR) + QString(LINEBREAK) + QString( QUIKMAN_COPYRIGHT ) + QString(LINEBREAK) + QString(LINEBREAK) + QString(LINEBREAK) + QString(QUIKMAN_ABOUT) + QString(LINEBREAK);
    abt += QString("\r\n");
    abt += QString("Version: ")+QString::number( QUIKMAN_VERSION_MAJOR ) + "." + QString::number( QUIKMAN_VERSION_MINOR ) + "." + QString::number( QUIKMAN_VERSION_REVISION )+ QString(LINEBREAK);
    abt += QString("Requires: ")+ QString(QUIKMAN_REQUIRES) + QString("\r\n");
    abt += QString("Provides: ")+ QString(QUIKMAN_PROVIDES) + QString("\r\n");
    QMessageBox::about(this, tr("About Quickman"), abt);
}

void MainWindow::getKeyValue( const QString & line, QString &key , QString &value ){
    int i = 0;
    bool flag = false;
    key = "";
    value = "";
    QString *current = &key;
    while ( i < line.length() ){
        char ch = line[i].toAscii();
        switch (ch) {
            case ' ':
            case '\t':
            case '\r':
            case '\n':
                    if ( flag ) {
                        if( current == &key ) {
                            current = &value;
                        }
                    }
                break;

            default:
                    if ( flag ) {
                        (*current) += ch;
                    } else {
                        (*current) += ch;
                        flag = true;
                    }
                break;
        }
        i++;
    }
}

void MainWindow::loadConfig(){
    QFile manconfig( QString(MAN_CONFIG));
    QString key("");
    QString value("");
    MainWindow::cout<<"INFO: Reading Man Configuration : "<<manconfig.fileName()<<endl;
    if(  manconfig.open(QFile::ReadOnly| QFile::Text) ){

        while ( !manconfig.atEnd() ){
            QString tmp = manconfig.readLine(0);
            QStringList tList = tmp.split("#");
            if ( (tList[0]).length() > 0 ){
                getKeyValue( tList[0], key , value );
                if ( key == "MANPATH" ){
                    MainWindow::cout<<"INFO: Adding Path :"<<value<<endl;
                    MainWindow::manpaths.append( value );
                }
            }
        }
        manconfig.close();
    } else {
        MainWindow::cout<<"WARN: Unable to open man config file, using default program paths"<<endl;
    }
    if( manpaths.size() == 0 ) {
        MainWindow::manpaths.append( QString("/usr/man") );
        MainWindow::manpaths.append( QString("/usr/share/man") );
        MainWindow::manpaths.append( QString("/usr/local/man") );
        MainWindow::manpaths.append( QString("/usr/local/share/man") );
        MainWindow::manpaths.append( QString("/usr/X11R6/man") );
        MainWindow::manpaths.append( QString("/opt/man") );
        MainWindow::manpaths.append( QString("/opt/share/man") );
        MainWindow::manpaths.append( QString("/opt/local/man") );
        MainWindow::manpaths.append( QString("/opt/local/share/man") );
    }

    MainWindow::msuffixes.append( QString("0") );
    MainWindow::msuffixes.append( QString("0x") );
    MainWindow::msuffixes.append( QString("0p") );
    MainWindow::msuffixes.append( QString("1") );
    MainWindow::msuffixes.append( QString("1x") );
    MainWindow::msuffixes.append( QString("1p") );
    MainWindow::msuffixes.append( QString("2") );
    MainWindow::msuffixes.append( QString("2x") );
    MainWindow::msuffixes.append( QString("2p") );
    MainWindow::msuffixes.append( QString("3") );
    MainWindow::msuffixes.append( QString("3x") );
    MainWindow::msuffixes.append( QString("3p") );
    MainWindow::msuffixes.append( QString("4") );
    MainWindow::msuffixes.append( QString("4x") );
    MainWindow::msuffixes.append( QString("4p") );
    MainWindow::msuffixes.append( QString("5") );
    MainWindow::msuffixes.append( QString("5x") );
    MainWindow::msuffixes.append( QString("5p") );
    MainWindow::msuffixes.append( QString("6") );
    MainWindow::msuffixes.append( QString("6x") );
    MainWindow::msuffixes.append( QString("6p") );
    MainWindow::msuffixes.append( QString("7") );
    MainWindow::msuffixes.append( QString("7x") );
    MainWindow::msuffixes.append( QString("7p") );
    MainWindow::msuffixes.append( QString("8") );
    MainWindow::msuffixes.append( QString("8x") );
    MainWindow::msuffixes.append( QString("8p") );
    MainWindow::msuffixes.append( QString("9") );
    MainWindow::msuffixes.append( QString("9x") );
    MainWindow::msuffixes.append( QString("9p") );
    MainWindow::msuffixes.append( QString("n") );



    MainWindow::suffixes.append( QString("*.gz") );
    MainWindow::suffixes.append( QString("*.bz2") );
    MainWindow::suffixes.append( QString("*.lzma") );
    MainWindow::suffixes.append( QString("*.Z") );
    MainWindow::suffixes.append( QString("*.1") );
    MainWindow::suffixes.append( QString("*.2") );
    MainWindow::suffixes.append( QString("*.3") );
    MainWindow::suffixes.append( QString("*.4") );
    MainWindow::suffixes.append( QString("*.5") );
    MainWindow::suffixes.append( QString("*.6") );
    MainWindow::suffixes.append( QString("*.7") );
    MainWindow::suffixes.append( QString("*.8") );

}

bool MainWindow::rebuildDB(){
    int i = 0;
    int j = 0;
    int k = 0;
    int  count = 0;

    QFile::remove( QString (QDir::homePath() + QString("/") + QString(QUIKMAN_DIR) +QString("/") + QString(QUIKMAN_DB) ) );
    aModel->clear();
    setHeaderLabels();
    MainWindow::cout<<"INFO: Reading Manual File Folders \n";
    while ( i < MainWindow::manpaths.size() ){
        j = 0;
        while ( j < MainWindow::msuffixes.size() ){
            QDir dir( MainWindow::manpaths[i] + QString("/man") + MainWindow::msuffixes[j] );
            QStringList tList = dir.entryList(MainWindow::suffixes, QDir::Files|QDir::NoSymLinks, QDir::Name|QDir::Type );
            k = 0;
            while ( k < tList.size() ){
                addToAll( tList[k], MainWindow::msuffixes[j], QString::number(i)) ;
                k++;
                count++;
                //statusBar()->showMessage(QString("Manual Pages Read : ")+QString::number(count));
            }
            j++;
        }
        i++;
    }
    //delete tmpString;
    aModel->sort(0);
    statusBar()->showMessage(QString("Total Manual Pages Present : ")+QString::number(count));
    MainWindow::cout<<"INFO: Found "<<count<<" Manual Files, Saving DB... \n";

    QFile dbFile (  QString (QDir::homePath() + QString("/") + QString(QUIKMAN_DIR) +QString("/") + QString(QUIKMAN_DB) ) );
    if ( dbFile.open( QFile::ReadWrite | QFile::Text ) ){
        QTextStream dbText( &dbFile );
        int rows = aModel->rowCount();
        for ( i=0; i<rows; i++ ){
            dbText<< aModel->data( aModel->index( i, 0 ) ).toString()<<","<<aModel->data( aModel->index( i, 1 ) ).toString()<<","<<aModel->data( aModel->index( i, 2 ) ).toString()<<"\r\n";
        }
        dbText.flush();
        dbFile.close();
        return true;
    } else {
        MainWindow::cout<<"ERRR: Unable to save dbfile : "<<dbFile.fileName()<<endl;
        return false;
    }
}

void MainWindow::loadModels(){
    int  count = 0;

    QFile dbFile (  QString (QDir::homePath() + QString("/") + QString(QUIKMAN_DIR) +QString("/") + QString(QUIKMAN_DB) ) );
    if ( dbFile.open( QFile::ReadOnly | QFile::Text ) ){
        MainWindow::cout<<"INFO: DBFile present "<<endl;
        QTextStream dbText( &dbFile );
        while ( !dbText.atEnd() ){
            QString tmp = dbText.readLine(0);
            if ( tmp.length() <= 2 ){
                continue;
            }
            QStringList tList = tmp.split(",");
            if( tList.size() < 3 ) {
                continue;
            }
            addToAll( tList[0], tList[1], tList[2]);
        }
        dbFile.close();
        MainWindow::cout<<"INFO: DBFile Contains "<<aModel->rowCount()<<" entries."<<endl;
    } else {
        MainWindow::cout<<"WARN: DBFile Not present, Rebuilding DB File : "<<dbFile.fileName()<<endl;
        rebuildDB();
    }

    QFile recentFile (  QString (QDir::homePath() + QString("/") + QString(QUIKMAN_DIR) +QString("/") + QString(QUIKMAN_RECENT) ) );
    QFileInfo   rFileInfo( recentFile.fileName() );
    QFile historyFile(  QString (QDir::homePath() + QString("/") + QString(QUIKMAN_DIR) +QString("/") + QString(QUIKMAN_HISTORY) ) );
    if (!recentFile.open(QFile::ReadOnly | QFile::Text)){
        MainWindow::cout<<"ERRR: Unable to open recent file :"<<recentFile.fileName()<<endl;
        return;
    }
    if (!historyFile.open(QFile::ReadOnly | QFile::Text)){
        MainWindow::cout<<"ERRR: Unable to open history file :"<<historyFile.fileName()<<endl;
        recentFile.close();
        return;
    }
    QTextStream recent(&recentFile );
    QTextStream history(&historyFile );


    recentGood   = true;
    QDateTime d  = rFileInfo.lastModified();
    QDateTime d2 = QDateTime::currentDateTime();

    if ( d.date() < d2.date() ){
        recentGood = false;
    }

    MainWindow::cout<<"INFO: Reading Recent \n";
    count = 0;
    while ( !recent.atEnd() ){
        QString tmp = recent.readLine(0);
        //MainWindow::cout<<tmp<<endl;
        if ( tmp.length() <= 2 ){
            continue;
        }
        QStringList tlist = tmp.split(",");
        if( tlist.size() < 4 ) {
            continue;
        }
        if ( ! recentGood ) {
            addUniqueToHistory( tlist[0], tlist[1], tlist[2], QDateTime::fromString(tlist[3]), true );
        }
        else {
            addUniqueToRecent( tlist[0], tlist[1], tlist[2], QDateTime::fromString(tlist[3]), true );
        }
    }

    MainWindow::cout<<"INFO: Read "<<rModel->rowCount()<<" Recent Entries"<<endl;
    MainWindow::cout<<"INFO: Reading History \n";
    while ( !history.atEnd() ){
        QString tmp = history.readLine(0);
        if ( tmp.length() <= 2 ){
            continue;
        }
        QStringList tlist = tmp.split(",");
        if ( tlist.size() == 4 ) {
            addUniqueToHistory( tlist[0], tlist[1], tlist[2], QDateTime::fromString(tlist[3]), true );
        }
    }
    MainWindow::cout<<"INFO: Read "<<hModel->rowCount()<<" History Entries"<<endl;
    recentFile.close();
    historyFile.close();

    if ( ! recentGood ) {
        QFile::remove( recentFile.fileName() );
    }
}

void MainWindow::loadSearch(QList<QStandardItem*> *l){
    QModelIndex i = aModel->indexFromItem( (*l)[0] );
    QStandardItem *name = aModel->item( i.row(), 0 );
    QStandardItem *sect = aModel->item( i.row(), 1 );
    QStandardItem *ptid = aModel->item( i.row(), 2 );
    if ( name && sect && ptid ) {
        viewManual( name->text(), sect->text(), ptid->text() );
    } else {
        MainWindow::cout<<"WARN: No defaut manual will be displayed \n";
    }
}

void MainWindow::lookupManual( const QString &name ){
    QList<QStandardItem *> fl = aModel->findItems( name , Qt::MatchStartsWith, 0);
    if ( fl.size() != 0 ){
        loadSearch( & fl );
        return;
    } else {
        MainWindow::cout<<"WARN: Munual for : "<<name<<" not found \n";
        if ( name != "man.1" ) {
            loadDefaultManual();
        }
    }
}

void MainWindow::loadDefaultManual(){
    if ( rModel->rowCount() == 0 ) {
        lookupManual( "man.1");
    } else {
        rModel->sort ( 3, Qt::DescendingOrder );
        QStandardItem *name = rModel->item( 0, 0 );
        QStandardItem *sect = rModel->item( 0, 1 );
        QStandardItem *ptid = rModel->item( 0, 2 );
        viewManual( name->text(), sect->text(), ptid->text() );
    }
}

void MainWindow::saveModels(){
    int i =0;
    QString rfname  = QDir::homePath() + "/" + QString(QUIKMAN_DIR) + "/" + QString(QUIKMAN_RECENT) ;
    QFile recentFile ( rfname + ".tmp" );
    QFile historyFile( QString( QDir::homePath() + QString("/") + QString(QUIKMAN_DIR) +QString("/") + QString(QUIKMAN_HISTORY) ) );
    if (!recentFile.open(QIODevice::ReadWrite | QIODevice::Text)){
        MainWindow::cout<<"ERRR: Unable to open recent file :"<<recentFile.fileName()<<endl;
         return;
    }
    if (!historyFile.open(QIODevice::ReadWrite | QIODevice::Text)){
        MainWindow::cout<<"ERRR: Unable to open history file :"<<historyFile.fileName()<<endl;
         recentFile.close();
         return;
    }
    QTextStream recent(&recentFile );
    QTextStream history(&historyFile );
    QFileInfo   rFileInfo( recentFile.fileName() );

    recent.seek( recentFile.size() );

    int rows = rModel->rowCount();
    for ( i=0; i<rows; i++ ){
        recent<< rModel->data( rModel->index( i, 0 ) ).toString()<<","<<rModel->data( rModel->index( i, 1 ) ).toString()<<","<<rModel->data( rModel->index( i, 2 ) ).toString()<<","<<rModel->data( rModel->index( i, 3 ) ).toString()<<"\r\n";
    }
    recent.flush();

    history.seek( historyFile.size() );
    rows = hModel->rowCount();
    for ( i=0; i<rows; i++ ){
        history<<hModel->data( hModel->index( i, 0 ) ).toString()<<","<<hModel->data( hModel->index( i, 1 ) ).toString()<<","<<hModel->data( hModel->index( i, 2 ) ).toString()<<","<<hModel->data( rModel->index( i, 3 ) ).toString()<<"\r\n";
    }
    history.flush();
    recentFile.close();
    historyFile.close();
    QFile::remove( rfname );
    QFile::rename( recentFile.fileName(), rfname );
}

void MainWindow::clearRecent(){
    //printf ("Clearing \n");
    rModel->clear();
    QFile::remove( QDir::homePath() + QString("/") + QString(QUIKMAN_DIR) +QString("/") + QString(QUIKMAN_RECENT) );
    setHeaderLabels();
}

void MainWindow::clearHistory(){
    //printf ("Clear History \n");
    hModel->clear();
    QFile::remove( QDir::homePath() + QString("/") + QString(QUIKMAN_DIR) +QString("/") + QString(QUIKMAN_HISTORY) );
    setHeaderLabels();
}


void MainWindow::openManLink( const QUrl & url ){
    MainWindow::cout<<"INFO: Accessing In page MAN Url : "<<url.toString()<<endl;
}

//void MainWindow::finExeCmd(int exitcode){
//    MainWindow::cout<<"INFO: Executed Cmd :"<<exitcode<<endl;
//}
//
//void MainWindow::startExeCmd(){
//    MainWindow::cout<<"INFO: Started  Cmd "<<endl;
//}

bool MainWindow::executeCmd( const QString &cmd, const QString &output){
    MainWindow::cout<<"INFO: Executing Cmd :"<<cmd <<" > "<<output<<endl;
    p->setStandardOutputFile(output);
    p->start( cmd );
    if ( p->waitForFinished() ) {
        return true;
    } else {
        MainWindow::cout<<"INFO: Executing Cmd failed "<<endl;
        return false;
    }
}

void MainWindow::readHtml( const QString &htmlFile, QString &data ) {
    QFile fin( htmlFile );
    if ( fin.open( QFile::ReadOnly|QFile::Text ) ){
        QTextStream tin( &fin );
        data = tin.readAll();
        fin.close();
    }
}

void MainWindow::loadHtml( const QString &htmlFile ){
    //manView->load(QUrl(QString("file://")+htmlFile));
    //manTextDoc->addResource( QTextDocument::HtmlResource, QUrl(QString("file://")+htmlFile) );
    QString data("");
    readHtml( htmlFile, data );
    manTextDoc->setHtml( data );
    MainWindow::cout<<"INFO: Loading HTML : "<<htmlFile<<endl;
}

QString* MainWindow::dereferenceManual ( const QString &name, const QString &section , const QString &pathid){
    QString file(MainWindow::manpaths[pathid.toInt()]+"/man"+section+"/"+name);
    QStringList nlist= name.split(".");
    QString suffix ;
    QString cmd;
    QString cmd2;
    QString nfile;

    if ( nlist.size() >= 2 ) {
        suffix = nlist[nlist.size()-1];
        if ( nlist.size() >= 3 ){
            nlist.removeLast();
            nfile = nlist.join(QString("."));
            nfile = QDir::tempPath() + "/" + QString(QUIKMAN_DIR) + "/" + nfile;
            if ( ! QFile::exists( nfile ) ) {
                if ( suffix == "gz" ) {
                    cmd   = "gzip -c -d "+file;
                } else if ( suffix == "bz2" ){
                    cmd   = "bzip2 -c -d "+file;
                } else if ( suffix == "lzma" ){
                    cmd   = "lzma -c -d "+file;
                } else if ( suffix == "Z" ){
                    cmd   = "gzip -c -d "+file;
                } else {
                    suffix = "";
                    printf("WARN: No Compression Used \n");
                    nfile = nlist.join(QString("."));
                    nfile = QDir::tempPath() + "/" + QString(QUIKMAN_DIR) + "/" + nfile;
                    cmd   = "cat "+ file;
                }
                if ( !executeCmd( cmd, nfile ) ) {
                    MainWindow::cout<<"ERRR: Uncompress Command Failed :"<<cmd<<endl;
                    return new QString("");
                }
            }
        } else {
            suffix = "";
            nfile = QDir::tempPath() + "/" + QString(QUIKMAN_DIR) + "/" + name;
            if ( ! QFile::exists( nfile ) ){
                QFile::copy( file, nfile );
            }
        }
    } else {
        MainWindow::cout<<"ERRR: Could not determine extension of the file :"<<name<<endl;
        return new QString("");
    }

    QFile fobj ( nfile );
    if ( fobj.size() <= MIN_MAN_SIZE ) {
        if ( fobj.open( QFile::ReadOnly | QFile::Text ) ) {
            QTextStream tobj( &fobj );
            QString derefString = tobj.readLine(0);
            QStringList tList   = derefString.split("/");
            if ( tList.size() == 2 ) {
                fobj.close();
                if ( suffix != "" ) {
                    tList[1] += "."+suffix;
                }
                return dereferenceManual( tList[1], section, pathid );
            } else {
                MainWindow::cout<<"ERRR: Deref Error, Pattern Mismatch : "<<derefString<<endl;
                return new QString("");
            }
        } else {
            MainWindow::cout<<"ERRR: Deref Error, File Open Error : "<<nfile<<endl;
            return new QString("");
        }
    } else {
        return new QString(nfile);
    }
}

void MainWindow::viewManual( const QString &name, const QString &section , const QString &pathid){
    if ( name == currentName &&  section == currentSection && pathid == currentPathid ) {
        MainWindow::cout<<"INFO: Currently displaying same manual \n";
        return;
    } else {
        currentName    = name;
        currentSection = section;
        currentPathid  = pathid;
    }

    QString *nfile = dereferenceManual ( name , section, pathid );
    if ( !nfile )
        return;
    if (*nfile == "" ) {
        delete nfile;
        return;
    }
    //QString cmd = QString("groff -man -Thtml ") + (*nfile);
    QString cmd = QString("man2html ") + (*nfile);
    *nfile += ".html";
    if ( !QFile::exists( *nfile ) ) {
        if ( executeCmd( cmd , *nfile ) ) {
                loadHtml(*nfile);
        } else {
            MainWindow::cout<<"ERRR: Execute Command Failed , Will not Load File: "<<nfile<<endl;
            return;
        }
    } else {
        loadHtml(*nfile);
    }
    delete nfile;
    setWindowTitle(appName + " : " + currentName);
}

void MainWindow::openManualFromAll(const QModelIndex &mindex){
    QStandardItem *name = aModel->item( mindex.row(), 0 );
    QStandardItem *sect = aModel->item( mindex.row(), 1 );
    QStandardItem *ptid = aModel->item( mindex.row(), 2 );
    viewManual( name->text(), sect->text(), ptid->text() );
    addUniqueToRecent( name->text(), sect->text(), ptid->text(), QDateTime::currentDateTime() );
}

void MainWindow::openManualFromRecent(const QModelIndex &mindex){
    QStandardItem *name = rModel->item( mindex.row(), 0 );
    QStandardItem *sect = rModel->item( mindex.row(), 1 );
    QStandardItem *ptid = rModel->item( mindex.row(), 2 );
    viewManual( name->text(), sect->text(), ptid->text() );
}

void MainWindow::openManualFromHistory(const QModelIndex &mindex){
    QStandardItem *name = hModel->item( mindex.row(), 0 );
    QStandardItem *sect = hModel->item( mindex.row(), 1 );
    QStandardItem *ptid = hModel->item( mindex.row(), 2 );
    viewManual( name->text(), sect->text(), ptid->text() );
    addUniqueToRecent( name->text(), sect->text(), ptid->text(), QDateTime::currentDateTime() );
}

void MainWindow::doNothing(){
    printf("doing Nothing \n");
}

void MainWindow::pathSetting(){
}

//void MainWindow::zoomIn(){
//    //manView->setZoomFactor( manView->zoomFactor() + DEFAULT_ZOOM_INC );
//}
//
//void MainWindow::zoomOut(){
//    //manView->setZoomFactor( manView->zoomFactor() - DEFAULT_ZOOM_INC );
//}



void MainWindow::fSearch(){
    QTextDocument::FindFlags flags = 0x0000;
    if ( sCase->checkState() ){
        flags |= QTextDocument::FindCaseSensitively;
    }
    if ( sWords->checkState() ) {
        flags |= QTextDocument::FindWholeWords;
    }
    QTextCursor cur = manText->textCursor();
    if ( sRegex->checkState() ) {
        cur = manTextDoc->find(QRegExp( sText->text() ), cur, flags );
    } else {
        cur = manTextDoc->find(sText->text(), cur, flags );
    }
    manText->setTextCursor ( cur );
}

void MainWindow::bSearch(){
    QTextDocument::FindFlags flags = 0x0000;
    if ( sCase->checkState() ){
        flags |= QTextDocument::FindCaseSensitively;
    }
    if ( sWords->checkState() ) {
        flags |= QTextDocument::FindWholeWords;
    }
    flags |= QTextDocument::FindBackward;
    QTextCursor cur = manText->textCursor();
    if ( sRegex->checkState() ) {
        cur = manTextDoc->find(QRegExp( sText->text() ), cur, flags );
    } else {
        cur = manTextDoc->find(sText->text(), cur, flags );
    }
    manText->setTextCursor ( cur );
}

void MainWindow::searchClear(){
    sText->clear();
}

void MainWindow::addUniqueToRecent(const QString &name, const QString &section, const QString &pathid, const QDateTime &date, bool append){
     QList<QStandardItem *>  l;
     QList<QStandardItem *>  fl = rModel->findItems( name );
     if ( fl.size() != 0 ) {
         QModelIndex i = rModel->indexFromItem( fl[0] );
         rModel->removeRow( i.row() );
     }
     QStandardItem *sname, *ssection, *spathid, *sdate;
     sname = new QStandardItem(name);
     sname->setFlags( Qt::ItemIsSelectable|Qt::ItemIsEnabled );
     ssection = new QStandardItem(section);
     ssection->setFlags( Qt::ItemIsSelectable|Qt::ItemIsEnabled );
     spathid = new QStandardItem(pathid);
     spathid->setFlags( Qt::ItemIsSelectable|Qt::ItemIsEnabled );
     sdate = new QStandardItem(date.toString());
     sdate->setFlags( Qt::ItemIsSelectable|Qt::ItemIsEnabled );
     l.append( sname );
     l.append( ssection );
     l.append( spathid );
     l.append( sdate );
     if ( append)
        rModel->appendRow( l );
     else
        rModel->insertRow( 0, l );
}

void MainWindow::addUniqueToHistory(const QString &name, const QString &section, const QString &pathid, const QDateTime &date, bool append){
     QList<QStandardItem *> l;
     QList<QStandardItem *>  fl = hModel->findItems( name );
     if ( fl.size() != 0 ) {
         QModelIndex i = hModel->indexFromItem( fl[0] );
         hModel->removeRow( i.row() );
     }
     QStandardItem *sname, *ssection, *spathid, *sdate;
     sname = new QStandardItem(name);
     sname->setFlags( Qt::ItemIsSelectable|Qt::ItemIsEnabled );
     ssection = new QStandardItem(section);
     ssection->setFlags( Qt::ItemIsSelectable|Qt::ItemIsEnabled );
     spathid = new QStandardItem(pathid);
     spathid->setFlags( Qt::ItemIsSelectable|Qt::ItemIsEnabled );
     sdate = new QStandardItem(date.toString());
     sdate->setFlags( Qt::ItemIsSelectable|Qt::ItemIsEnabled );
     l.append( sname );
     l.append( ssection );
     l.append( spathid );
     l.append( sdate );
     if ( append)
        hModel->appendRow( l );
     else
        hModel->insertRow( 0, l );
}

void MainWindow::addToAll(const QString &name, const QString &section, const QString &pathid){
     QList<QStandardItem *> l;
     QStandardItem *sname, *ssection, *spathid;
     sname = new QStandardItem(name);
     sname->setFlags( Qt::ItemIsSelectable|Qt::ItemIsEnabled );
     ssection = new QStandardItem(section);
     ssection->setFlags( Qt::ItemIsSelectable|Qt::ItemIsEnabled );
     spathid = new QStandardItem(pathid);
     spathid->setFlags( Qt::ItemIsSelectable|Qt::ItemIsEnabled );
     l.append( sname );
     l.append( ssection );
     l.append( spathid );
     aModel->appendRow( l );
}


